<?php
declare(strict_types=1);

namespace App\Bac\Middleware;

use App\Constants\Business;
use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use Hyperf\Context\Context;
use Psr\Log\LoggerInterface;
use Hyperf\HttpServer\Request;
use Hyperf\HttpServer\Response;
use Hyperf\Di\Annotation\Inject;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use App\Bac\Model\RBAC\Admin as AdminModel;
use Psr\Http\Server\RequestHandlerInterface;

class AuthorizationMiddleware implements MiddlewareInterface
{
    #[Inject]
    protected Request $request;
    #[Inject]
    protected Response $response;

    protected LoggerInterface $logger;

    public function __construct()
    {
        $this->logger = getLogger('http-back');
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // 允许跨域
        $response = Context::get(ResponseInterface::class);
        if ($request->getMethod() == 'OPTIONS') {
            return $response;
        }
        // 登录验证
        $resp = $this->validateAuth();
        return $resp ?: $handler->handle($request);
    }

    /**
     * 登录验证
     * @author gaolei 2022/3/21 11:55 上午
     */
    private function validateAuth()
    {
        @Context::destroy(Business::CONTEXT_KEY_AUTH_ADMIN);
        $pathInfo = str_replace(URL_PREFIX_CONTROL, '', $this->request->getRequestUri());
        if (!in_array($pathInfo, ['/login'])) {
            $authorization = $this->request->getHeader('authorization')[0] ?? null;
            try {
                $authAdmin = AdminModel::getAuthAdmin($authorization);
            } catch (\Throwable $e) {
                $authAdmin = null;
                $errorMsg = '登录验证失败，请先登录';
                if ($e instanceof BusinessException && $e->getCode() === ErrorCode::ERR_GONE) {
                    $errorMsg = '登录已过期，请重新登录';
                }
            }
            if (!$authAdmin) {
                $schema = $this->request->getMethod() . ":" . $this->request->url();
                $this->logger->error($errorMsg . PHP_EOL . print_r([
                        'schema' => $schema,
                        'header' => formatLogArray($this->request->getHeaders()),
                        'query' => formatLogArray($this->request->getQueryParams()),
                        'body' => $this->request->getParsedBody(),
                    ], true));
                return $this->response->withStatus(401)->raw($errorMsg);
            }
            // 验证账户状态
            if ($authAdmin->state !== AdminModel::STATE_NORMAL) {
                $authAdmin->auth_key = null;
                $authAdmin->save();
                return $this->response->withStatus(401)->raw('账户状态异常，请联系管理员');
            }
            // 将登录用户绑定到 上下文
            Context::set(Business::CONTEXT_KEY_AUTH_ADMIN, $authAdmin);
        }
        return null;
    }

}
